アクションAPIのリビジョン
まとめ
Flutter では、Intent
通常バインドされるオブジェクトです
を使用してキーボードのキーの組み合わせにShortcuts
ウィジェット。
アンIntent
にバインドできるAction
、
これにより、アプリケーションの状態を更新したり、他の操作を実行したりできます。
この API を使用する過程で、いくつかの欠点が判明しました。
そのため、操作を簡単にするために Actions API を更新しました。
使って理解すること。
以前のアクション API 設計では、アクションはLocalKey
にActionFactory
新しいものを生み出したのはAction
毎回invoke
メソッドが呼び出されました。
現在の API では、アクションはIntent
にAction
インスタンス (Map<Type, Action>
)、
また、呼び出しごとに新たに作成されるわけではありません。
コンテクスト
元の Actions API 設計は、からアクションを呼び出すことを目的としていました。 ウィジェットを作成し、それらのアクションをウィジェットのコンテキストで動作させることができます。 チームはアクションを使用してきましたが、それにはいくつかの制限があることがわかりました。 対処する必要があった設計:
-
アクションはウィジェット階層の外部から呼び出すことができませんでした。 この例には、コマンドのスクリプトの処理が含まれます。 一部のアンドゥ アーキテクチャと一部のコントローラ アーキテクチャ。
-
ショートカットキーからへのマッピング
Intent
そしてそしてAction
データ構造が複雑であるため、必ずしも明確ではありませんでした。 マッピングされたLogicalKeySet =>Intent、そしてLocalKey
=>ActionFactory
。新しいマッピングはまだLogicalKeySet
にIntent
しかしその後、マッピングされますType
(Intent
と入力してください)Action
これはより直接的であり、 インテントのタイプがマッピングに記述されているため、読み取り可能です。 -
アクションのキー バインドが別の部分にあった場合、 ウィジェット階層では、常に可能であるとは限りませんでした。
Intent
かどうかを決定するために必要な状態にアクセスするため。 インテント/アクションを有効にするかどうかを指定する必要があります。
これらの問題に対処するために、API にいくつかの重要な変更を加えました。
アクションのマッピングがより直感的になりました。
有効なインターフェイスは、Action
クラス。
いくつかの不要な引数がAction
のinvoke
メソッドとそのコンストラクター、およびアクションが許可されました
呼び出しメソッドから結果を返します。
アクションはジェネリックスに作成され、次のタイプを受け入れます。Intent
彼らは扱います、そしてLocalKeys
もはや識別には使用されませんでした
実行するアクションとそのタイプIntent
代わりに使用されます。
これらの変更の大部分は、次の PR で行われました。アクションAPIの改訂とAction.enabled を有効にする 代わりに isEnabled(Intent インテント)、そして に詳しく説明されていますデザイン 博士。
変更内容の説明
上記の問題に対処するために加えられた変更は次のとおりです。
- の
Map<LocalKey, ActionFactory>
に与えられたのはActions
ウィジェット 今はMap<Type, Action<Intent>>
(タイプはインテントのタイプです) アクションに渡されます)。 - の
isEnabled
メソッドはから移動されましたIntent
クラスへAction
クラス。 - の
FocusNode
に対する議論Action.invoke
とActions.invoke
メソッドが削除されました。 - アクションを呼び出しても、
Action
。 - の
LocalKey
に対する議論Intent
コンストラクターが削除されました。 - の
LocalKey
に対する議論CallbackAction
取り除かれた。 - の
Action
クラスはジェネリックになりました (Action<T extends Intent>
) 良い方向へ タイプセーフティ。 - の
OnInvokeCallback
によって使われたCallbackAction
もう必要ありませんFocusNode
口論。 - の
ActionDispatcher.invokeAction
署名は受け入れられないように変更されました オプションFocusNode
ですが、代わりにオプションのBuildContext
。 - の
LocalKey
静的定数 (慣例により名前付きキー)Action
サブクラスは削除されました。 - の
Action.invoke
とActionDispatcher.invokeAction
メソッドが返されるようになりました アクションを呼び出した結果Object
。 - の
Action
クラスの状態変化をリッスンできるようになりました。 - の
ActionFactory
typedef は使用されなくなったため、削除されました。
アナライザーの故障例
以下に、次のような場合に発生する可能性のあるアナライザーの障害の例をいくつか示します。 Actions API の古い使用法が問題の原因である可能性があります。詳細 エラーの内容は異なる可能性があり、これらが原因で他の障害が発生する可能性があります。 変化します。
error: MyActionDispatcher.invokeAction' ('bool Function(Action<Intent>, Intent, {FocusNode focusNode})') isn't a valid override of 'ActionDispatcher.invokeAction' ('Object Function(Action<Intent>, Intent, [BuildContext])'). (invalid_override at [main] lib/main.dart:74)
error: MyAction.invoke' ('void Function(FocusNode, Intent)') isn't a valid override of 'Action.invoke' ('Object Function(Intent)'). (invalid_override at [main] lib/main.dart:231)
error: The method 'isEnabled' isn't defined for the type 'Intent'. (undefined_method at [main] lib/main.dart:97)
error: The argument type 'Null Function(FocusNode, Intent)' can't be assigned to the parameter type 'Object Function(Intent)'. (argument_type_not_assignable at [main] lib/main.dart:176)
error: The getter 'key' isn't defined for the type 'NextFocusAction'. (undefined_getter at [main] lib/main.dart:294)
error: The argument type 'Map<LocalKey, dynamic>' can't be assigned to the parameter type 'Map<Type, Action<Intent>>'. (argument_type_not_assignable at [main] lib/main.dart:418)
移行ガイド
既存のコードを更新するには大幅な変更が必要な領域 新しい API に。
事前定義されたアクションのアクションマッピング
アクション マップを更新するには、Actions
のウィジェット
Flutter の事前定義されたアクション:ActivateAction
とSelectAction
、 以下をせよ:
- の引数の型を更新します。
actions
口論 - 特定のインスタンスを使用する
Intent
のクラスShortcuts
マッピングではなく、Intent(TheAction.key)
実例。
移行前のコード:
class MyWidget extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: <LogicalKeySet, Intent> {
LogicalKeySet(LogicalKeyboardKey.enter): Intent(ActivateAction.key),
},
child: Actions(
actions: <LocalKey, ActionFactory>{
Activate.key: () => ActivateAction(),
},
child: Container(),
)
);
}
}
移行後のコード:
class MyWidget extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: <LogicalKeySet, Intent> {
LogicalKeySet(LogicalKeyboardKey.enter): ActivateIntent,
},
child: Actions(
actions: <Type, Action<Intent>>{
ActivateIntent: ActivateAction(),
},
child: Container(),
)
);
}
}
カスタムアクション
カスタム アクションを移行するには、LocalKeys
定義したものを次のものに置き換えますIntent
サブクラス、
引数の型をactions
の議論Actions
ウィジェット。
移行前のコード:
class MyAction extends Action {
MyAction() : super(key);
/// The [LocalKey] that uniquely identifies this action to an [Intent].
static const LocalKey key = ValueKey<Type>(RequestFocusAction);
@override
void invoke(FocusNode node, MyIntent intent) {
// ...
}
}
class MyWidget extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: <LogicalKeySet, Intent> {
LogicalKeySet(LogicalKeyboardKey.enter): Intent(MyAction.key),
},
child: Actions(
actions: <LocalKey, ActionFactory>{
MyAction.key: () => MyAction(),
},
child: Container(),
)
);
}
}
移行後のコード:
// You may need to create new Intent subclasses if you used
// a bare LocalKey before.
class MyIntent extends Intent {
const MyIntent();
}
class MyAction extends Action<MyIntent> {
@override
Object invoke(MyIntent intent) {
// ...
}
}
class MyWidget extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: <LogicalKeySet, Intent> {
LogicalKeySet(LogicalKeyboardKey.enter): MyIntent,
},
child: Actions(
actions: <Type, Action<Intent>>{
MyIntent: MyAction(),
},
child: Container(),
)
);
}
}
Actions
とIntents
引数付き
カスタムインテント引数を使用するアクションまたは状態を保持するアクションを更新するには、
の引数を変更する必要がありますinvoke
方法。
以下の例では、コードは
アクションインスタンスの一部としてインテント内の引数を指定します。
これは、古い設計には新しいインスタンスがあるためです。
実行されるたびに作成されるアクションの、
そして結果として得られるアクションは、ActionDispatcher
状態を記録するため。
以下の移行後のコードの例では、
新しいMyAction
結果として状態を返します
電話のinvoke
、新しいインスタンスは作成されないため、
呼び出しごとに。この状態は呼び出し元に返されます。Actions.invoke
、 またActionDispatcher.invokeAction
、
アクションの呼び出し方法に応じて異なります。
移行前のコード:
class MyIntent extends Intent {
const MyIntent({this.argument});
final int argument;
}
class MyAction extends Action {
MyAction() : super(key);
/// The [LocalKey] that uniquely identifies this action to an [Intent].
static const LocalKey key = ValueKey<Type>(RequestFocusAction);
int state;
@override
void invoke(FocusNode node, MyIntent intent) {
// ...
state = intent.argument;
}
}
移行後のコード:
class MyIntent extends Intent {
const MyIntent({this.argument});
final int argument;
}
class MyAction extends Action<MyIntent> {
@override
int invoke(Intent intent) {
// ...
return intent.argument;
}
}
タイムライン
リリースされたバージョン: 1.18
安定版リリース: 1.20
参考文献
API ドキュメント:
Action
ActionDispatcher
Actions
Intent
Shortcuts
関連する問題:
- 問題 53276
関連する PR:
- アクションAPIの改訂
- 代わりに Action.enabled を isEnabled(Intent インテント) にします